package com.enumdemo.multi_channel_distribution.demo1;

import java.util.Random;

import com.enumdemo.multi_channel_distribution.demo1.face.Item;

/**
 * 多路分发就是指在调用a.plus(b)，a和b都不知道确切类型，也能让他们正常交互。
 * 如果想使用两路分发，那么必须有两个方法调用，第一个方法调用决定第一个未知类型
 * ，第二个方法调用决定第二个未知类型。要利用多路分发，程序员必须为每一个类型提供给一个实际的方法调用
 * 。一般而言，程序员需要设定好某种配置，以便一个方法调用能够引出更多的方法调用，从而能在这个过程中处理多个类型。 下面是个“石头 剪刀
 * 布”（RoShamBo）游戏的例子 （from: thinking in java）：
 * 
 * @author Administrator
 *
 */
public class RoShamBo1 {

	static final int SIZE = 20;
	private static Random rand = new Random(47);

	public static Item newItem() {
		switch (rand.nextInt(3)) {
		default:
		case 0:
			return new Scissors();
		case 1:
			return new Paper();
		case 2:
			return new Rock();
		}
	}

	/**
	 * RoshamBol.match()有2个item参数，通过Item.compete()方法开始2路分发，要判定a的类型，
	 * 分发机制会在a的实际类型的compete()内部起到分发作用。compete()方法通过eval()来为另一个类型实现第二次分发，
	 * 将自身(this)作为参数调用eval()，能够调用重载过的eval()方法，这能够保留第一次分发的类型信息，第二次分发完成时，
	 * 就能知道两个Item对象的具体类型了。
	 * 
	 * @param a
	 * @param b
	 */
	// 用上述方法，就能避免 if else的书写和获取对象具体类型的方法
	// 这种方法的精妙之处在于，通过调用 item1的compete方法，实现对item1的类型的分发，而在item1的compete方法中，
	// 用通过调用item2的eval方法，将自身this作为参数，实现了Item2中eval方法的分发
	public static void match(Item a, Item b) {
		System.out.println(a + " vs. " + b + ": " + a.compete(b));
	}

	public static void main(String[] args) {
		for (int i = 0; i < SIZE; i++)
			match(newItem(), newItem());
	}

}
